home *** CD-ROM | disk | FTP | other *** search
- /*
- ** wt -- a 3d game engine
- **
- ** Copyright (C) 1994 by Chris Laurel
- ** email: claurel@mr.net
- ** snail mail: Chris Laurel, 5700 W Lake St #208, St. Louis Park, MN 55416
- **
- ** This program is free software; you can redistribute it and/or modify
- ** it under the terms of the GNU General Public License as published by
- ** the Free Software Foundation; either version 2 of the License, or
- ** (at your option) any later version.
- **
- ** This program is distributed in the hope that it will be useful,
- ** but WITHOUT ANY WARRANTY; without even the implied warranty of
- ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- ** GNU General Public License for more details.
- **
- ** You should have received a copy of the GNU General Public License
- ** along with this program; if not, write to the Free Software
- ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
- #include <stdio.h>
- #include <string.h>
- #include <stdlib.h>
- #include <ctype.h>
- #include <limits.h>
- #include <math.h>
-
- #include "wt.h"
- #include "error.h"
- #include "fixed.h"
- #include "wtmem.h"
- #include "list.h"
- #include "table.h"
- #include "texture.h"
- #include "world.h"
- #include "worldfile.h"
-
-
- #define TEXTURE_NAME_MAX_LENGTH 32
- #define STRING_TOKEN_MAX_LENGTH 256
-
- #define IS_STRING_TOKEN_CHAR(c) (isalpha(c) || isdigit(c) || \
- (c) == '/' || c == '.')
- #define COMMENT_CHAR ';'
-
- typedef struct {
- char name[TEXTURE_NAME_MAX_LENGTH + 1];
- int index;
- } Texture_node;
-
- typedef enum {
- Token_string,
- Token_real,
- Token_integer,
- Token_EOF
- } Token_type;
-
-
- static void parse_world(FILE *fp, World *w);
- static void parse_vertex(FILE *fp, World *w);
- static void parse_wall(FILE *fp, World *w);
- static void parse_region(FILE *fp, World *w);
- static void parse_texture(FILE *fp, World *w);
- static int get_texture_index(char *name);
- static List_result find_list_name(void *node, void *data);
- static Token_type get_string_token(FILE *fp, char *tokenbuf);
- static Token_type get_real_token(FILE *fp, fixed *f);
- static Token_type get_integer_token(FILE *fp, int *i);
- static int skip_whitespace(FILE *fp);
- static void parse_error(char *message);
-
- static List *texture_list;
- static int line_number;
-
-
- World *read_world_file(FILE *fp)
- {
- World *w;
-
- w = new_world();
- texture_list = new_list();
- parse_world(fp, w);
- delete_list(texture_list);
-
- return w;
- }
-
-
- void parse_world(FILE *fp, World *w)
- {
- char tokenbuf[STRING_TOKEN_MAX_LENGTH];
-
- while (get_string_token(fp, tokenbuf) != Token_EOF) {
- if (strcmp(tokenbuf, "texture") == 0)
- parse_texture(fp, w);
- else if (strcmp(tokenbuf, "wall") == 0)
- parse_wall(fp, w);
- else if (strcmp(tokenbuf, "region") == 0)
- parse_region(fp, w);
- else if (strcmp(tokenbuf, "vertex") == 0)
- parse_vertex(fp, w);
- else
- parse_error("unknown structure type");
- }
- }
-
-
- void parse_vertex(FILE *fp, World *w)
- {
- Vertex v;
-
-
- if (get_real_token(fp, &v.x) != Token_real)
- parse_error("number expected");
- if (get_real_token(fp, &v.y) != Token_real)
- parse_error("number expected");
-
- add_vertex(w, &v);
- }
-
-
- void parse_region(FILE *fp, World *w)
- {
- char texture_name[STRING_TOKEN_MAX_LENGTH];
- int texture_index;
- Region r;
-
- if (get_real_token(fp, &r.floor) != Token_real)
- parse_error("number expected");
- if (get_real_token(fp, &r.ceiling) != Token_real)
- parse_error("number expected");
-
- /* floor texture */
- if (get_string_token(fp, texture_name) != Token_string)
- parse_error("texture name expected");
- texture_index = get_texture_index(texture_name);
- if (texture_index < 0 || texture_index > TABLE_SIZE(w->textures))
- parse_error("non-existent texture");
- else
- r.floor_tex = WORLD_TEXTURE(w, texture_index);
-
- /* ceiling texture */
- if (get_string_token(fp, texture_name) != Token_string)
- parse_error("texture name expected");
- if (strcmp(texture_name, "sky") == 0)
- r.ceiling_tex = NULL;
- else {
- texture_index = get_texture_index(texture_name);
- if (texture_index < 0 || texture_index > TABLE_SIZE(w->textures))
- parse_error("non-existent texture");
- else
- r.ceiling_tex = WORLD_TEXTURE(w, texture_index);
- }
-
- add_region(w, &r);
- }
-
-
- void parse_wall(FILE *fp, World *w)
- {
- Wall wall;
- char texture_name[STRING_TOKEN_MAX_LENGTH];
- int texture_index;
- int front_region, back_region;
- int vertex1, vertex2;
- fixed wall_length;
-
-
- /* vertices */
- if (get_integer_token(fp, &vertex1) != Token_integer)
- parse_error("integer expected");
- if (get_integer_token(fp, &vertex2) != Token_integer)
- parse_error("integer expected");
- if (vertex1 < 0 || vertex1 > TABLE_SIZE(w->vertices))
- parse_error("invalid vertex number");
- if (vertex2 < 0 || vertex2 > TABLE_SIZE(w->vertices))
- parse_error("invalid vertex number");
- wall.vertex1 = &WORLD_VERTEX(w, vertex1);
- wall.vertex2 = &WORLD_VERTEX(w, vertex2);
-
- /* texture */
- if (get_string_token(fp, texture_name) != Token_string)
- parse_error("texture name expected");
- texture_index = get_texture_index(texture_name);
- if (texture_index < 0 || texture_index > TABLE_SIZE(w->textures))
- parse_error("non-existent texture");
- else
- wall.surface_texture = WORLD_TEXTURE(w, texture_index);
-
- if (strcmp(texture_name, "sky") == 0)
- wall.sky = True;
- else
- wall.sky = False;
-
- /* front and back regions */
- if (get_integer_token(fp, &front_region) != Token_integer)
- fatal_error("non-existent region");
- if (get_integer_token(fp, &back_region) != Token_integer)
- fatal_error("non-existent region");
- if (front_region < 0 || front_region > TABLE_SIZE(w->regions))
- fatal_error("non-existent region");
- if (back_region < 0 || back_region > TABLE_SIZE(w->regions))
- fatal_error("non-existent region");
- wall.front = &WORLD_REGION(w, front_region);
- wall.back = &WORLD_REGION(w, back_region);
-
- /* Texture phase and scale. This code is somewhat more complicated than
- ** you'd expect, since the texture scale must be normalized to the
- ** wall length.
- */
- if (get_real_token(fp, &wall.xscale) != Token_real)
- parse_error("number expected");
- if (get_real_token(fp, &wall.yscale) != Token_real)
- parse_error("number expected");
- if (get_real_token(fp, &wall.xphase) != Token_real)
- parse_error("number expected");
- if (get_real_token(fp, &wall.yphase) != Token_real)
- parse_error("number expected");
- wall_length =
- FLOAT_TO_FIXED(sqrt(FIXED_TO_FLOAT(wall.vertex2->x -
- wall.vertex1->x) *
- FIXED_TO_FLOAT(wall.vertex2->x -
- wall.vertex1->x) +
- FIXED_TO_FLOAT(wall.vertex2->y -
- wall.vertex1->y) *
- FIXED_TO_FLOAT(wall.vertex2->y -
- wall.vertex1->y)));
- wall.yscale = fixmul(wall.yscale,
- INT_TO_FIXED(wall.surface_texture->height));
- wall.xscale = fixmul(fixmul(wall.xscale,
- INT_TO_FIXED(wall.surface_texture->width)),
- wall_length);
-
- add_wall(w, &wall);
- }
-
-
- void parse_texture(FILE *fp, World *w)
- {
- char texture_name[STRING_TOKEN_MAX_LENGTH];
- char filename[STRING_TOKEN_MAX_LENGTH];
- char texture_path[PATH_MAX + STRING_TOKEN_MAX_LENGTH];
- Texture *t;
- Texture_node *tn;
-
-
- if (get_string_token(fp, texture_name) != Token_string)
- parse_error("texture name expected");
- if (strlen(texture_name) >= TEXTURE_NAME_MAX_LENGTH)
- parse_error("texture name too long");
-
- if (get_string_token(fp, filename) != Token_string)
- parse_error("texture file name expected");
-
- sprintf(texture_path, HostDirFileStr, TEXTURE_PATH, filename);
- t = read_texture_file(texture_path);
-
- tn = wtmalloc(sizeof(Texture_node));
- strcpy(tn->name, texture_name);
- tn->index = TABLE_SIZE(w->textures);
-
- add_node(texture_list, tn);
- add_texture(w, t);
- }
-
-
- int get_texture_index(char *name)
- {
- List *l;
-
- l = scan_list(texture_list, name, find_list_name);
- if (l == NULL)
- return -1;
- else
- return ((Texture_node *) l->next->node)->index;
- }
-
-
- List_result find_list_name(void *node, void *data)
- {
- char *name = (char *) data;
- Texture_node *tnode = (Texture_node *) node;
-
- if (strcmp(name, tnode->name) == 0)
- return List_success;
- else
- return List_failure;
- }
-
-
- Token_type get_string_token(FILE *fp, char *tokenbuf)
- {
- int length = 0;
- int c;
-
- c = skip_whitespace(fp);
- if (c == EOF)
- return Token_EOF;
-
- while (c != EOF && IS_STRING_TOKEN_CHAR(c)) {
- if (length >= STRING_TOKEN_MAX_LENGTH - 1)
- parse_error("string too long");
-
- tokenbuf[length] = c;
- length++;
-
- c = getc(fp);
- }
-
- ungetc(c, fp);
- tokenbuf[length] = '\0';
-
- return Token_string;
- }
-
-
- Token_type get_real_token(FILE *fp, fixed *f)
- {
- double d;
- int c;
-
- c = skip_whitespace(fp);
- if (c == EOF)
- return Token_EOF;
-
- ungetc(c, fp);
- if (fscanf(fp, "%lf", &d) != 1)
- parse_error("numeric constant expected");
-
- *f = FLOAT_TO_FIXED(d);
-
- return Token_real;
- }
-
-
- Token_type get_integer_token(FILE *fp, int *i)
- {
- int c;
-
- c = skip_whitespace(fp);
- if (c == EOF)
- return Token_EOF;
-
- ungetc(c, fp);
- if (fscanf(fp, "%d", i) != 1)
- parse_error("integer constant expected");
-
- return Token_integer;
- }
-
-
- int skip_whitespace(FILE *fp)
- {
- int c = getc(fp);
-
- while (c == ' ' || c == '\t' || c == '\n' || c == COMMENT_CHAR) {
- if (c == COMMENT_CHAR) {
- while (c != EOF && c != '\n')
- c = getc(fp);
- }
-
- if (c == '\n')
- line_number++;
- c = getc(fp);
- }
-
- return c;
- }
-
-
- void parse_error(char *message)
- {
- fatal_error("Error in world file (line %d): %s\n", line_number,
- message);
- }
-